package lt.ntec.danblog.server.blog.model.gae;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.jdo.JDOException;
import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import lt.ntec.danblog.server.blog.model.Post;
import lt.ntec.danblog.server.blog.model.PostDAO;
import lt.ntec.danblog.server.core.model.CommentDAO;
import lt.ntec.danblog.server.core.model.DAOException;
import lt.ntec.danblog.server.core.model.Tag;
import lt.ntec.danblog.server.core.model.TagDAO;
import lt.ntec.danblog.server.core.model.UserDAO;
import lt.ntec.danblog.server.core.model.gae.JDOBaseDAO;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.inject.Inject;

class JDOBlogPostDAO extends JDOBaseDAO<Post> implements PostDAO {

    private TagDAO tagDao;
    private UserDAO userDao;
    private CommentDAO commentDao;

    @Inject
    public JDOBlogPostDAO(PersistenceManager pm, TagDAO tagDao, UserDAO userDao, CommentDAO commentDao) {
        super(pm);
        this.tagDao = tagDao;
        this.commentDao = commentDao;
        this.userDao = userDao;
    }

    @Override
    public Class<BlogPost> getEntityClass() {
        return BlogPost.class;
    }

    @Override
    public void delete(Post entity) {
        try {
            //pm.currentTransaction().begin();
            pm.deletePersistent(entity);
            //pm.currentTransaction().commit();
        } catch (Exception e) {
            throw new DAOException(e);
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Post> getLastPosts() {
        String q = "select from " + getEntityClass().getName();
        Query query = pm.newQuery(q);
        query.setOrdering("date desc");
        query.setRange(0, 5);
        Object list = query.execute();
        List<Post> greetings = (List<Post>) list;
        populateTagsForList(greetings);
        populateAuthorForList(greetings);
        return greetings;
    }

    @Override
    public Post getById(Long id) {
        Post post = null;
        try {
            post = pm.getObjectById(getEntityClass(), id);
            post.setTags(tagDao.getTagsByParent(post));
        } catch (JDOObjectNotFoundException e) {
            return null;
        } catch (Exception e) {
            throw new DAOException(e);
        }
        return post;
    }

    @Override
    public Long save(Post entity) {
        try {
            pm.currentTransaction().begin();
            Key authorKey;
            if (entity.getAuthor().getId() == null) {
                Long id = userDao.save(
                        entity.getAuthor());
                authorKey = KeyFactory.createKey(entity.getAuthor().getClass().getSimpleName(),
                        id);
                ((BlogPost) entity).setAuthorKey(authorKey);
            }

            pm.makePersistent(entity);


            pm.currentTransaction().commit();

            for (Tag tag : entity.getTags()) {
                tag.addParent(entity);
            }

            //pm.currentTransaction().begin();
            pm.makePersistentAll(entity.getTags());
            //pm.currentTransaction().commit();

        } catch (JDOException e) {
            throw new DAOException(e);
        }
        return entity.getId();
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Post> getList() {
        Query query = pm.newQuery(getEntityClass());
        List<Post> list = (List<Post>) (query.execute());
        populateTagsForList(list);
        populateAuthorForList(list);
        return list;
    }

    private void populateTagsForList(List<Post> posts) {
        for (Post post : posts) {
            Set<Tag> tags = new HashSet<Tag>();
            for (Key key : ((BlogPost) post).getTagsKey()) {
                tags.add(tagDao.getById(key.getId()));
            }
            post.setTags(tags);
        }
    }

    private void populateAuthorForList(List<Post> posts) {
        for (Post post : posts) {
            Key key = ((BlogPost) post).getAuthorKey();
            ((BlogPost) post).setAuthor(userDao.getById(key.getId()));
        }
    }
}
